Visualization | Social Network Analysis (ver.2.20260428)¶

Dr. Chan, Chun-Hsiang @ Department of Geography,
National Taiwan Normal University, Taipei, Taiwan

In [1]:
# import packages
import numpy as np
import pandas as pd
import networkx as nx
import matplotlib.pyplot as plt
from pyvis import network as net
from jaal import Jaal
/Users/toodou/miniconda3/envs/toodou/lib/python3.10/site-packages/dash_bootstrap_components/_table.py:5: UserWarning: 
The dash_html_components package is deprecated. Please replace
`import dash_html_components as html` with `from dash import html`
  import dash_html_components as html

Create a Random Graph¶

In [2]:
# create Erdos Renyi random graph
G = nx.erdos_renyi_graph(50, 0.2, seed=21, directed=False)
In [3]:
# set options
options = {
    "font_size": 8,
    "node_size": 100,
    "node_color": "#A0CBE2",
    "edge_color": "brown",
    "linewidths": 0.1,
    "width": 0.08,
}
In [4]:
# circular
plt.subplots(figsize=[12,6], dpi=100)
nx.draw_circular(G,  **options, with_labels = True)
ax = plt.gca()
ax.margins(0.001)
plt.axis("off")
plt.show()
No description has been provided for this image
In [5]:
# kamada kawai
plt.subplots(figsize=[12,6], dpi=100)
nx.draw_kamada_kawai(G,  **options, with_labels = True)
ax = plt.gca()
ax.margins(0.001)
plt.axis("off")
plt.show()
No description has been provided for this image
In [6]:
# shell
plt.subplots(figsize=[12,6], dpi=100)
nx.draw_shell(G,  **options, with_labels = True)
ax = plt.gca()
ax.margins(0.001)
plt.axis("off")
plt.show()
No description has been provided for this image
In [7]:
# spectral
plt.subplots(figsize=[12,6], dpi=100)
nx.draw_spectral(G,  **options, with_labels = True)
ax = plt.gca()
ax.margins(0.001)
plt.axis("off")
plt.show()
No description has been provided for this image
In [8]:
# spring
plt.subplots(figsize=[12,6], dpi=100)
nx.draw_spring(G,  **options, with_labels = True)
ax = plt.gca()
ax.margins(0.001)
plt.axis("off")
plt.show()
No description has been provided for this image
In [9]:
plt.subplots(figsize=[12,6], dpi=100)
nx.draw_random(G,  **options, with_labels = True)
ax = plt.gca()
ax.margins(0.001)
plt.axis("off")
plt.show()
No description has been provided for this image

Pyvis¶

In [11]:
# create vis network 
visG = net.Network(notebook=True, height="800px", width="100%", bgcolor="#222222",
                   font_color="white", filter_menu=True, select_menu=True, cdn_resources='remote')
# import graph from networkx
visG.from_nx(G)
# show
visG.show_buttons() #filter_=['physics']
visG.show('pyvis_ex.html') # save file
pyvis_ex.html
Out[11]:
In [12]:
# extract networkx node to dataframe
G_nodes = pd.DataFrame.from_records(np.vstack(list(G.nodes)), columns=['ID'])
# add size with random values
G_nodes['importance'] = abs(np.random.normal(15, 12, G_nodes.shape[0]))
# add group with random values
G_nodes['group'] = np.random.randint(5, size=G_nodes.shape[0])+1
# add node label with random values
G_nodes['code'] = 'S_'+G_nodes['ID'].astype('str')
# preview data
G_nodes.head()
Out[12]:
ID importance group code
0 0 16.161601 2 S_0
1 1 34.763198 2 S_1
2 2 8.745326 5 S_2
3 3 22.068353 1 S_3
4 4 22.587786 4 S_4
In [13]:
# extract networkx edge to dataframe
G_edges = pd.DataFrame.from_records(np.vstack(list(G.edges)), columns=['source','target'])
# add weight with random values
G_edges['weight'] = abs(np.random.normal(100, 25, G_edges.shape[0]))**2/1000
# preview data
G_edges.head()
Out[13]:
source target weight
0 0 1 14.839815
1 0 11 8.733637
2 0 14 10.822140
3 0 18 8.210414
4 0 23 11.063825
In [14]:
color_map = {1:'#CCFF00', 2:'#CCCC33', 3:'#CC9966', 4:'#CC6699', 5:'#CC33CC', 6:'#CC00FF',  
                 7:'#9900FF', 8:'#6600CC', 9:'#660066', 10:'#660033', 11:'#CC99FF', 12:'#FFCCFF', 
                 13:'#FFFFCC', 14:'#FF3300', 15:'#333333', 16:'#666666'} 
options = {
        'edge_color': '#FFDEA2',
        'width': .5,
        'with_labels': False,
        'font_weight': 'regular',
    }
In [15]:
# initialize 
g = net.Network(height="800px", width="100%", bgcolor="#222222", font_color="white",  
                filter_menu=True, select_menu=True, cdn_resources='remote')
# add node
for i in range(len(G_nodes['code'])): 
    g.add_node(int(G_nodes['ID'][i]), size=int(G_nodes['importance'][i]), label=G_nodes['code'][i],
               group=int(G_nodes['group'][i]))
# add edge
for i in range(len(G_edges)):
    g.add_edge(int(G_edges['source'][i]), int(G_edges['target'][i]), weight=G_edges['weight'][i])
# add options
g.set_template_dir = None
g.show_buttons()
# export
g.show('adv_ex.html', notebook=False)
adv_ex.html

Export¶

In [16]:
G_nodes.to_csv('ex_node.csv', index=False)
G_edges.to_csv('ex_edge.csv', index=False)

Jaal¶

In [17]:
# rename columns for Jaal
G_edges.columns = ['from', 'to', 'weight'] # Jaal reinforce source & target should be named as from and to
G_nodes.columns = ['id', 'importance', 'group', 'code'] # "size" is reserved word in Jaal
In [18]:
# change the data type of group column into String
G_nodes['group'] = G_nodes['group'].astype(str)
In [19]:
# compute the mean and standard deviation for division
mean = np.mean(G_edges['weight'])
stddev = np.std(G_edges['weight'], ddof=1)

# using value to define the division
G_edges['strength'] = 'Middle'
G_edges.loc[G_edges['weight'] > mean + 1*stddev, 'strength'] = 'Higher'
G_edges.loc[G_edges['weight'] < mean + 1*stddev, 'strength'] = 'Lower'
In [20]:
# simple demo
Jaal(G_edges, G_nodes).plot()
Parsing the data...Done
In [21]:
# set for directed graph
Jaal(G_edges, G_nodes).plot(directed=True)
Parsing the data...Done
No trigger
In [22]:
# init Jaal and run server
Jaal(G_edges, G_nodes).plot(vis_opts={'height': '600px', # change height
                                      'interaction':{'hover': True}, # turn on-off the hover 
                                      'physics':{'stabilization':{'iterations': 100}}},
                           ) # define the convergence iteration of network
Parsing the data...Done
No trigger
No trigger
inside color node group
inside color edge strength
Modifying node size using  importance
Modifying edge size using  weight
inside color node group
inside color edge strength
Modifying node size using  importance
Modifying edge size using  weight
inside color node group
inside color edge strength
Modifying node size using  importance
Modifying edge size using  weight
In [ ]:
 
In [ ]:
 
In [ ]:
 
In [ ]:
 
In [ ]:
 
In [ ]: